package com.date.demo02;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.Date;

public class Test {
    public static void main(String[] args){
        System.out.println("JDK8 java.time包提供了新的日期和时间API");
        /**
         * java.time包提供了新的日期和时间API，主要涉及的类型有：
         * 本地日期和时间：LocalDateTime，LocalDate，LocalTime；
         * 带时区的日期和时间：ZonedDateTime；
         * 时刻：Instant；
         * 时区：ZoneId，ZoneOffset；
         * 时间间隔：Duration。
         * 以及一套新的用于取代 SimpleDateFormat 的格式化类型 DateTimeFormatter。
         *
         * 和旧的API相比，新API严格区分了时刻、本地日期、本地时间和带时区的日期时间，并且，对日期和时间进行运算更加方便。
         *
         * 此外，新API修正了旧API不合理的常量设计：
         *
         * Month的范围用 1~12 表示1月到12月；
         * Week的范围用 1~7 表示周一到周日。
         * 最后，新API的类型几乎全部是不变类型（和String类似），可以放心使用不必担心被修改。
         */

        // LocalDateTime
        // 以下严格按照ISO 8601格式打印
        /**
         * 注意ISO 8601规定的日期和时间分隔符是T。标准格式如下：
         *
         * 日期：yyyy-MM-dd
         * 时间：HH:mm:ss
         * 带毫秒的时间：HH:mm:ss.SSS
         * 日期和时间：yyyy-MM-dd'T'HH:mm:ss
         * 带毫秒的日期和时间：yyyy-MM-dd'T'HH:mm:ss.SSS
         */
        // 1.获取当前日期
        LocalDate d = LocalDate.now();
        System.out.println(d); // 2021-12-22
        // 2.获取当前时间
        LocalTime t = LocalTime.now();
        System.out.println(t); // 17:47:50.596 精确到毫秒
        // 3.获取当前日期和时间
        LocalDateTime l = LocalDateTime.now();
        System.out.println(l); // 2021-12-22T17:49:06.284
        /**
         * 本地日期和时间通过now()获取到的总是以当前默认时区返回的，
         * 上述代码由于执行一行代码总会消耗一点时间，因此，3个类型的日期和时间很可能对不上（时间的毫秒数基本上不同）
         * 为了保证获取到同一时刻的日期和时间，可以改写如下：
         */
        System.out.println("====更改写法 固定时间====");
        // 当前日期和时间
        LocalDateTime dt = LocalDateTime.now();
        System.out.println(dt);
        // 获取日期
        LocalDate dt_date = dt.toLocalDate();
        System.out.println(dt_date); //
        // 获取时间点
        LocalTime dt_time = dt.toLocalTime();
        System.out.println(dt_time);

        /**
         * 创建指定日期方式
         * 1、使用 of 方法
         * 2、字符串创建，使用 parse 方法
         */
        // 反过来，可以指定日期和时间 创建LocalDateTime，可以通过of()方法
        // 方式一
        LocalDateTime dt2 = LocalDateTime.of(2019, 12, 20, 15, 16, 17);
        System.out.println(dt2); // 2019-12-20T15:16:17
        // 方式二
        LocalDate d2 = LocalDate.of(2019,11,30); // 2019-11-30
        LocalTime t2 = LocalTime.of(15,16,17); // 15:16:17
        LocalDateTime d3 = LocalDateTime.of(d2,t2);
        System.out.println(d3); // 2019-11-20T15:16:17
        // 方式三 字符串转为 LocalDateTime、LocalDate、LocalTime形式
        // 严格按照ISO 8601的格式
        LocalDateTime str_turn_ldt = LocalDateTime.parse("2019-10-20T12:11:18");
        System.out.println(str_turn_ldt); // 2019-10-20T12:11:18
        LocalDate str_turn_ld = LocalDate.parse("2021-12-10");
        System.out.println(str_turn_ld); //  2021-12-10
        LocalTime str_turn_lt = LocalTime.parse("12:12:20");
        System.out.println(str_turn_lt); //  12:12:20

        // 字符串和日期之间转换
        // 1. 日期 --> 字符串 toString()
        String str_date = d3.toString();
        System.out.println(str_date); // 2019-11-20T15:16:17

        // 2.字符串 --> 日期 parse()
        LocalDateTime date_4 = LocalDateTime.parse("2019-11-20T15:16:17");
        LocalDate d4 = LocalDate.parse("2019-11-19");
        LocalTime t4 = LocalTime.parse("15:16:17");
        System.out.println(date_4);
        System.out.println(d4);
        System.out.println(t4);

        /**
         * 由于 ISO 8601 的格式 带有 T 作为分隔符，或者根据自定义格式输出日期。
         * 那么 就需要使用 DateTimeFormatter。JDK8新增的，格式化输出日期
         * DateTimeFormatter 作用
         * 1.把 LocalDateTime 转换为 字符串输出
         * 2.把非ISO 8601格式的字符串转化为 LocalDateTime 类型（非ISO 8601格式 表示不是 yyyy-MM-ddTHH:mm:ss 格式）
         */
        System.out.println("=== 日期格式化 ===");
        // 创建实例
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        // 1.日期 --> 字符串 format
        String dtf_date_str = dtf.format(date_4);
        System.out.println(dtf_date_str);
        // 2.字符串 --> 日期 parse
        System.out.println("===== 字符串转日期 =====");
        String change_date = "2012/12/15 15:16:17"; // 这里的格式需要和 DateTimeFormatter.ofPattern（格式） 中的格式保持一致
        LocalDateTime turn_dates = LocalDateTime.parse(change_date,dtf); // 2012-12-15T15:16:17
        System.out.println(turn_dates);

        String test_date = "2012-06-19T18:16:17"; // 这里的格式需要和 DateTimeFormatter.ofPattern（格式） 中的格式保持一致

        LocalDateTime turn_test_date = LocalDateTime.parse(test_date); // 2012-12-15T15:16:17
        System.out.println(turn_test_date);
        System.out.println("======测试====");


        // 使用 LocalDateTime 之间进行运算操作
        System.out.println("=== 日期之间运算 ===");
        LocalDateTime diy_local_date = LocalDateTime.of(2020,10,10,10,10,10);
        System.out.println(dtf.format(diy_local_date)); // 2020/10/10 10:10:10
        // 加五天时间
        LocalDateTime add_time = diy_local_date.plusDays(5);
        System.out.println(dtf.format(add_time)); // 2020/10/15 10:10:10
        // 再减去三个小时
        LocalDateTime sub_time = diy_local_date.minusHours(3);
        System.out.println(dtf.format(sub_time)); // 2020/10/10 07:10:10
        // 链式操作 减去一个月 再减去10个小时
        LocalDateTime relation_time = diy_local_date.minusMonths(1).minusHours(10);
        System.out.println(dtf.format(relation_time)); // 2020/09/10 00:10:10

        /**
         * 月份是自动会调整的 例如从2019-10-31减去1个月得到的结果是2019-09-30，因为9月没有31日。
         * 对日期和时间进行调整则使用withXxx()方法，例如：withHour(15)会把10:11:12变为15:11:12
         * 调整的方法如下：
         * 调整年：withYear()
         * 调整月：withMonth()
         * 调整日：withDayOfMonth()
         * 调整时：withHour()
         * 调整分：withMinute()
         * 调整秒：withSecond()
         */
        System.out.println("===时间调整====");
        LocalDateTime dt3 = LocalDateTime.of(2021,5,21,20,13,50);
        System.out.println(dtf.format(dt3)); // 2021/05/21 20:13:50
        // 把日期调整为 31 日
        // 如果当前月份没有 31号 那么就会报异常
        // java.time.DateTimeException: Invalid date 'APRIL 31'
        LocalDateTime dt4 = dt3.withDayOfMonth(31); // 2021/05/31 20:13:50
        System.out.println(dtf.format(dt4));
        // 调整月份以及时间 链式操作
        LocalDateTime dt5 = dt4.withMonth(7).minusHours(10);
        System.out.println(dtf.format(dt5)); //2021/07/31 10:13:50

        LocalDateTime ldt = LocalDateTime.of(2021,10,31,10,10,20);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        System.out.println(dateTimeFormatter.format(ldt)); // 2021-10-31 10:10:20
        // 调整月份为 9月 日期自动变为 30
        LocalDateTime ldt2 = ldt.withMonth(9);
        System.out.println(dateTimeFormatter.format(ldt2)); // 2021-09-30 10:10:20
    }
}
